﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Epsilon.Expr;

namespace Epsilon.Parse
{
    [Serializable]
    public class ParseException : Exception
    {
        public ParseException() { }
        public ParseException(string message) : base(message) { }
        public ParseException(string message, Exception inner) : base(message, inner) { }
        protected ParseException(
          System.Runtime.Serialization.SerializationInfo info,
          System.Runtime.Serialization.StreamingContext context)
            : base(info, context) { }
    }

    public partial class Parser
    {
        List<Token> tokens = new List<Token>();
        int pos = 0;
        Process p;

        public Parser(List<Token> t, string f)
        {
            tokens = t;
            pos = 0;
            p = new Process(f);
        }

        void Error(string message)
        {
            string s = "Error during parsing - " + message;
            s += "\nprocess: " + p.Name + "\nline: " + tokens[pos].Line + " col: " + tokens[pos].Col;
            throw new ParseException(s);
        }

        bool MatchPeek(TokenType type, string val)
        {
            if (pos >= tokens.Count)
                return false;
            Token t = tokens[pos];
            return (t.Type == type && t.Value == val);
        }

        void Match(TokenType type, string val)
        {
            bool b = MatchPeek(type, val);
            if (!b)
            {
                Error("Expected " + val + " found " + CurrentToken().Value);
            }
            pos++;
        }

        bool CheckType(TokenType type)
        {
            if (pos >= tokens.Count)
                return false;
            return tokens[pos].Type == type;
        }

        Token CurrentToken()
        {
            return tokens[pos];
        }

        void Chomp()
        {
            pos++;
        }

        void UnChomp()
        {
            pos--;
        }

        public Process Parse()
        {
            while (pos < tokens.Count)
            {
                if (MatchPeek(TokenType.Symbol, "-"))
                    ParseAttribute();
                else
                    p.Functions.Add(ParseFunction());
                Match(TokenType.Symbol, ".");
            }

            bool hasMain = false;
            for (int i = 0; i < p.Functions.Count; i++)
            {
                if (p.Functions[i].Name == "main" && p.Functions[i].Arguments.Count == 0)
                    hasMain = true;
            }

            if (p.Name == "")
                throw new ParseException("Each process requires a -process attribute");

            if (!hasMain)
                throw new ParseException("Process " + p.Name + " does not have a function main/0");

            return p;
        }
    }
}
